home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 1 / Amiga Tools.iso / disk-tools / cd-tools / amicdrom / checkcd.c < prev    next >
C/C++ Source or Header  |  1994-06-06  |  13KB  |  498 lines

  1. /* Checkcd.c:
  2.  *
  3.  * Performs consistency checks on a ISO 9660 CD.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18.  
  19. #include <dos/var.h>
  20. #include <clib/dos_protos.h>
  21. #include <clib/exec_protos.h>
  22. #include <clib/exec_protos.h>
  23. #include <clib/utility_protos.h>
  24.  
  25. #include "cdrom.h"
  26. #include "iso9660.h"
  27. #include "rock.h"
  28.  
  29. #ifdef AZTEC_C
  30. #include <pragmas/dos_lib.h>
  31. #include <pragmas/exec_lib.h>
  32. #include <pragmas/utility_lib.h>
  33. #endif
  34.  
  35. #ifdef LATTICE
  36. #include <pragmas/dos_pragmas.h>
  37. #include <pragmas/exec_pragmas.h>
  38. #include <pragmas/utility_pragmas.h>
  39. extern struct Library *SysBase, *DOSBase;
  40. #endif
  41.  
  42. #if defined(_DCC) && defined(REGISTERED)
  43. #include <pragmas/dos_pragmas.h>
  44. #include <pragmas/exec_pragmas.h>
  45. extern struct Library *SysBase, *DOSBase;
  46. #endif
  47.  
  48. #define STD_BUFFERS 20
  49. #define FILE_BUFFERS 2
  50.  
  51. CDROM *g_cd = NULL;
  52. char g_the_device[80];
  53. int g_the_unit;
  54. t_ulong g_memory_type = MEMF_CHIP;
  55. t_ulong g_check_sector;
  56. char *g_check_name;
  57. prim_vol_desc g_pvd;
  58. int g_path_table_records = 0;
  59.  
  60. struct Library *UtilityBase;
  61.  
  62. #define TU(x,o)  (t_ulong)(((unsigned char *)(x))[o])
  63. #define GET721(x) (TU(x,0) + (TU(x,1) << 8))
  64. #define GET722(x) (TU(x,1) + (TU(x,0) << 8))
  65. #define GET731(x) (TU(x,0) + (TU(x,1) << 8) + (TU(x,2) << 16) + (TU(x,3) << 24))
  66. #define GET732(x) (TU(x,3) + (TU(x,2) << 8) + (TU(x,1) << 16) + (TU(x,0) << 24))
  67.  
  68. /* Check consistency of a 7.2.3 field: */
  69.  
  70. void Check_723 (void *p_buf, int p_offset)
  71. {
  72.   t_uchar *buf = (t_uchar *) (p_buf) + (p_offset - 1);
  73.   t_ulong l = buf[0] + (buf[1] << 8);
  74.   t_ulong m = buf[3] + (buf[2] << 8);
  75.   if (l != m) {
  76.     printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.2.3\n",
  77.             g_check_name, g_check_sector, p_offset);
  78.   }
  79. }
  80.  
  81. /* Check consistency of a 7.3.3 field: */
  82.  
  83. void Check_733 (void *p_buf, int p_offset)
  84. {
  85.   t_uchar *buf = (t_uchar *) p_buf + (p_offset - 1);
  86.   t_ulong l = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
  87.   t_ulong m = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
  88.   if (l != m) {
  89.     printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.3.3\n",
  90.             g_check_name, g_check_sector, p_offset);
  91.   }
  92. }
  93.  
  94. /* Check optional path tables: */
  95.  
  96. void Check_Optional_Path_Tables (void)
  97. {
  98.   t_ulong loc1, loc2;
  99.   t_uchar *buf1;
  100.   t_uchar *buf2;
  101.   int i;
  102.   
  103.   for (i=0; i<=1; i++) {
  104.   
  105.     int remain = g_pvd.path_size_m;
  106.  
  107.     if (i == 0)
  108.       loc1 = GET731((char*) &g_pvd.l_table),
  109.       loc2 = GET731((char *) &g_pvd.opt_l_table);
  110.     else
  111.       loc1 = g_pvd.m_table, loc2 = g_pvd.opt_m_table;
  112.     if (!loc2)
  113.       continue;
  114.  
  115.     for (;;) {
  116.     
  117.       if (!Read_Sector (g_cd, loc1)) {
  118.         printf ("ERROR: illegal sector %lu\n", loc1);
  119.         exit (1);
  120.       }
  121.       buf1 = g_cd->buffer;
  122.     
  123.       if (!Read_Sector (g_cd, loc2)) {
  124.         printf ("ERROR: illegal sector %lu\n", loc2);
  125.         exit (1);
  126.       }
  127.       buf2 = g_cd->buffer;
  128.  
  129.       if (memcmp (buf1, buf2, remain > 2048 ? 2048 : remain) != 0) {
  130.         printf ("ERROR: %c path table and optional %c path table differ"
  131.         " in sectors %lu and %lu\n",
  132.         i ? 'M' : 'L', i ? 'M' : 'L', loc1, loc2);
  133.       }
  134.  
  135.       if (remain > 2048)
  136.         remain -= 2048;
  137.       else
  138.         break;
  139.  
  140.       loc1++, loc2++;
  141.     }
  142.   }
  143. }
  144.  
  145. /* Get the path table record in sector p_loc with offset *p_offset. */
  146.  
  147. void Get_Path_Table_Record (t_uchar *p_buf, t_ulong p_loc, t_ulong *p_offset)
  148. {
  149.   t_ulong sector = p_loc + (*p_offset >> 11);
  150.   int len;
  151.  
  152.   if (!Read_Sector (g_cd, sector)) {
  153.     printf ("ERROR: illegal sector %lu\n", sector);
  154.     exit (1);
  155.   }
  156.   len = g_cd->buffer[*p_offset & 2047] + 8;
  157.   if (len & 1)
  158.     len++;
  159.  
  160.   if (len + (*p_offset & 2047) > 2048) {
  161.     int part1_len = 2048 - (*p_offset & 2047);
  162.     memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), part1_len);
  163.     if (!Read_Sector (g_cd, sector+1)) {
  164.       printf ("ERROR: illegal sector %lu\n", sector+1);
  165.       exit (1);
  166.     }
  167.     memcpy (p_buf + part1_len, g_cd->buffer, len - part1_len);
  168.   } else
  169.     memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), len);
  170.   
  171.   *p_offset += len;
  172. }
  173.  
  174. /* Test whether the L and the M path tables contain the same information: */
  175.  
  176. void Compare_L_And_M_Path_Table (void)
  177. {
  178.   t_ulong loc1 = GET731((char*) &g_pvd.l_table);
  179.   t_ulong loc2 = g_pvd.m_table;
  180.   t_ulong offset1 = 0;
  181.   t_ulong offset2 = 0;
  182.   static t_uchar buf1[256];
  183.   static t_uchar buf2[256];
  184.  
  185.   while (offset1 < g_pvd.path_size_m) {
  186.  
  187.     t_ulong tmp = offset1;
  188.  
  189.     Get_Path_Table_Record (buf1, loc1, &offset1);
  190.     Get_Path_Table_Record (buf2, loc2, &offset2);
  191.  
  192.     if (offset1 != offset2) {
  193.       printf ("ERROR: Length mismatch in L and M path table at offset %lu\n",
  194.                 tmp);
  195.       return;
  196.     }
  197.  
  198.     if (buf1[1] != buf2[1])
  199.       printf ("ERROR: Extended attribute record lengths differ in L and M"
  200.               " path table at offset %lu\n", offset1);
  201.  
  202.     if (memcmp (buf1+8, buf2+8, buf1[0]) != 0)
  203.       printf ("ERROR: directory identifiers differ in L and M path table "
  204.               "at offset %lu\n", offset1);
  205.  
  206.     if (GET731 (buf1+2) != GET732 (buf2+2))
  207.       printf ("ERROR: extent locations differ in L and M path table at"
  208.               " offset %lu\n", offset1);
  209.  
  210.     if (GET721 (buf1+6) != GET722 (buf2+6))
  211.       printf ("ERROR: parent directory numbers differ in L and M path table at"
  212.               " offset %lu\n", offset1);
  213.  
  214.     g_path_table_records++;
  215.   }
  216. }
  217.  
  218. /* Check consistency of path table and directory records: */
  219.  
  220. void Compare_Path_Table_With_Directory_Records (void)
  221. {
  222.   t_ulong loc = g_pvd.m_table;
  223.   t_ulong offset = 0;
  224.   static t_uchar buf[256];
  225.   int rec = 1;
  226.   VOLUME *vol;
  227.   CDROM_OBJ *obj;
  228.   CDROM_INFO info;
  229.   t_ulong pos;
  230.   t_bool warn_case = 0;
  231.  
  232.   vol = Open_Volume (g_cd, 0);
  233.   if (!vol) {
  234.     printf ("ERROR: cannot open volume\n");
  235.     exit (10);
  236.   }
  237.  
  238.   for (; offset < g_pvd.path_size_m; rec++) {
  239.     t_ulong tmp = offset;
  240.  
  241.     if ((rec & 7) == 1) {
  242.       printf ("\r   (%d of %d)",
  243.                 rec, g_path_table_records);
  244.       fflush (stdout);
  245.     }
  246.     Get_Path_Table_Record (buf, loc, &offset);
  247.     /* skip root record: */
  248.     if (rec == 1)
  249.       continue;
  250.     pos = GET732 (buf+2);
  251.     obj = Iso_Create_Directory_Obj (vol, pos);
  252.     if (!obj || !CDROM_Info (obj, &info)) {
  253.       printf ("\nERROR: cannot get information for directory at location %lu\n"
  254.               "(Path table offset = %lu)\n", pos, tmp);
  255.       exit (10);
  256.     }
  257.     if (info.name_length != buf[0] ||
  258.         Strnicmp ((UBYTE*) info.name, (UBYTE*) buf+8, info.name_length) != 0) {
  259.       printf ("\nERROR: names in path table and directory record differ for "
  260.               "directory at location %lu\n", pos);
  261.       printf ("Name in path table = ");
  262.       fwrite (buf+8, 1, info.name_length, stdout);
  263.       printf ("\nName in directory record = ");
  264.       fwrite (info.name, 1, info.name_length, stdout);
  265.       putchar ('\n');
  266.     } else if (!warn_case && memcmp (info.name, buf+8, info.name_length) != 0) {
  267.       printf ("\nWARNING: Directory names in path table and directory records "
  268.               "differ in case.\n");
  269.       warn_case = 1;
  270.     }
  271.     Close_Object (obj);
  272.   }
  273.   printf ("\r%75s\r", "");
  274.   Close_Volume (vol);
  275. }
  276.  
  277. /* Check optional path tables: */
  278.  
  279. void Check_Path_Tables (void)
  280. {
  281.   Check_Optional_Path_Tables ();
  282.   Compare_L_And_M_Path_Table ();
  283. }
  284.  
  285. /* Check primary volume descriptor: */
  286.  
  287. void Check_PVD (void)
  288. {
  289.   int loc = 16;
  290.   int pvd_pos = 0;
  291.   prim_vol_desc *pvd;
  292.  
  293.   do {
  294.     if (!Read_Sector (g_cd, loc)) {
  295.       printf ("ERROR: illegal sector %d\n", loc);
  296.       exit (1);
  297.     }
  298.     pvd = (prim_vol_desc *) g_cd->buffer;
  299.     if (memcmp (pvd->id, "CD001", 5) != 0) {
  300.       printf ("ERROR: missing standard identifier at sector %d\n", loc);
  301.       exit (10);
  302.     }
  303.     if (pvd->type > 4 && pvd->type < 255)
  304.       printf ("WARNING: unknown volume descriptor type at sector %d\n", loc);
  305.     if (pvd->version != 1)
  306.       printf ("WARNING: unknown volume descriptor version at sector %d\n", loc);
  307.     if (pvd->type == 1 && !pvd_pos)
  308.       pvd_pos = loc;
  309.     loc++;
  310.   } while (pvd->type != 255);
  311.  
  312.   if (!Read_Sector (g_cd, pvd_pos)) {
  313.     printf ("ERROR: illegal sector %d\n", loc);
  314.     exit (1);
  315.   }
  316.   pvd = (prim_vol_desc *) g_cd->buffer;
  317.   g_check_name = "primary volume descriptor";
  318.   g_check_sector = pvd_pos;
  319.   Check_733 (pvd, 81);
  320.   Check_723 (pvd, 121);
  321.   Check_723 (pvd, 125);
  322.   Check_723 (pvd, 129);
  323.   Check_733 (pvd, 133);
  324.   memcpy (&g_pvd, pvd, sizeof (g_pvd));
  325. }
  326.  
  327. void Check_Subdirectory (CDROM_OBJ *p_home, char *p_name)
  328. {
  329.   CDROM_OBJ *obj;
  330.   CDROM_INFO info;
  331.   /* VOLUME *vol = p_home->volume; */
  332.  
  333.   printf ("  %s\r", p_name);
  334.   fflush (stdout);
  335.  
  336.   if (obj = Open_Object (p_home, p_name)) {
  337.     unsigned long offset = 0;
  338.  
  339.     while (Examine_Next (obj, &info, &offset)) {
  340.       directory_record *dir = info.suppl_info;
  341.       g_check_name = "directory record";
  342.       g_check_sector = offset;
  343.       Check_733 (dir, 3);
  344.       Check_733 (dir, 11);
  345.       Check_723 (dir, 29);
  346.     }
  347.  
  348.     Close_Object (obj);
  349.   } else {
  350.     printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
  351.     return;
  352.   }
  353.  
  354.   if (obj = Open_Object (p_home, p_name)) {
  355.     unsigned long offset = 0;
  356.  
  357.     while (Examine_Next (obj, &info, &offset)) {
  358.       if (info.directory_f) {
  359.         char *name = malloc (strlen (p_name) + info.name_length + 2);
  360.     int len;
  361.     if (!name) {
  362.       fprintf (stderr, "out of memory\n");
  363.       exit (10);
  364.     }
  365.     if (Is_Top_Level_Object (obj))
  366.       name[0] = 0;
  367.     else
  368.       sprintf (name, "%s/", p_name);
  369.     len = strlen (name) + info.name_length;
  370.     memcpy (name + strlen (name), info.name, info.name_length);
  371.     name[len] = 0;
  372.     Check_Subdirectory (p_home, name);
  373.     free (name);
  374.       }
  375.     }
  376.     Close_Object (obj);
  377.   } else {
  378.     printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
  379.   }
  380.  
  381.   printf ("  %*s\r", strlen (p_name), "");
  382. }
  383.  
  384. void Check_Directories (void)
  385. {
  386.   VOLUME *vol;
  387.   CDROM_OBJ *home;
  388.  
  389.   if (!(vol = Open_Volume (g_cd, 1))) {
  390.     printf ("ERROR: cannot open volume; iso_errno = %d\n", iso_errno);
  391.     exit (10);
  392.   }
  393.  
  394.   if (!(home = Open_Top_Level_Directory (vol))) {
  395.     printf ("ERROR: cannot open top level directory; iso_errno = %d\n", iso_errno);
  396.     Close_Volume (vol);
  397.     exit (1);
  398.   }
  399.  
  400.   Check_Subdirectory (home, ":");
  401.  
  402.   Close_Object (home);
  403.   Close_Volume (vol);
  404. }
  405.  
  406. void Cleanup (void)
  407. {
  408.   if (g_cd)
  409.     Cleanup_CDROM (g_cd);
  410.  
  411.   if (UtilityBase)
  412.     CloseLibrary (UtilityBase);
  413. }
  414.  
  415. int Get_Device_And_Unit (void)
  416. {
  417.   int len;
  418.   char buf[10];
  419.   
  420.   len = GetVar ((UBYTE *) "CDROM_DEVICE", (UBYTE *) g_the_device,
  421.           sizeof (g_the_device), 0);
  422.   if (len < 0)
  423.     return 0;
  424.   if (len >= sizeof (g_the_device)) {
  425.     fprintf (stderr, "CDROM_DEVICE too long\n");
  426.     exit (1);
  427.   }
  428.   g_the_device[len] = 0;
  429.   
  430.   len = GetVar ((UBYTE *) "CDROM_UNIT", (UBYTE *) buf,
  431.           sizeof (buf), 0);
  432.   if (len < 0)
  433.     return 0;
  434.   if (len >= sizeof (buf)) {
  435.     fprintf (stderr, "CDROM_UNIT too long\n");
  436.     exit (1);
  437.   }
  438.   buf[len] = 0;
  439.   g_the_unit = atoi (buf);
  440.   
  441.   if (GetVar ((UBYTE *) "CDROM_FASTMEM", (UBYTE *) buf,
  442.       sizeof (buf), 0) > 0) {
  443.     fprintf (stderr, "using fastmem\n");
  444.     g_memory_type = MEMF_FAST;
  445.   }
  446.  
  447.   return 1;
  448. }
  449.  
  450. void main (int argc, char *argv[])
  451. {
  452.   atexit (Cleanup);
  453.  
  454.   if (!(UtilityBase = (struct Library *)
  455.          OpenLibrary ((UBYTE *) "utility.library", 37))) {
  456.     fprintf (stderr, "cannot open utility.library\n");
  457.     exit (1);
  458.   }
  459.  
  460.   if (!Get_Device_And_Unit ()) {
  461.     fprintf (stderr,
  462.       "Please set the following environment variables:\n"
  463.       "  CDROM_DEVICE    name of SCSI device\n"
  464.       "  CDROM_UNIT      unit number of CDROM drive\n"
  465.       "e.g.\n"
  466.       "  setenv CDROM_DEVICE scsi.device\n"
  467.       "  setenv CDROM_UNIT 2\n"
  468.       "Set the variable CDROM_FASTMEM to any value if you\n"
  469.       "want to use fast memory for SCSI buffers (does not work\n"
  470.       "with all SCSI devices!)\n"
  471.       );
  472.     exit (1);
  473.   }
  474.  
  475.   g_ignore_blocklength = TRUE;
  476.  
  477.   g_cd = Open_CDROM (g_the_device, g_the_unit, 1, g_memory_type,
  478.              STD_BUFFERS, FILE_BUFFERS);
  479.   if (!g_cd) {
  480.     fprintf (stderr, "cannot open CDROM, error code = %d\n", g_cdrom_errno);
  481.     exit (1);
  482.   }
  483.  
  484.   printf ("Checking primary volume descriptor...\n");
  485.   Check_PVD ();
  486.   printf ("Checking path tables...\n");
  487.   Check_Path_Tables ();
  488.   printf ("Comparing path table with directory records...\n");
  489.   Compare_Path_Table_With_Directory_Records ();
  490.  
  491.   printf ("Checking directories...\n");
  492.   Check_Directories ();
  493.  
  494.   printf ("All checks completed.\n");
  495.  
  496.   exit (0);
  497. }
  498.